﻿using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RongCloudSms.Configuration;
using RongCloudSms.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Zop;

namespace RongCloudSms.Service
{
    public class RongCloudService : IRongCloudService
    {
        private readonly RongCloudOption _option;
        private readonly IMongoCollection<MongoDBModel> _collection;
        private readonly IMongoCollection<MongoDBUserModel> _collection_user;
        private readonly ILogger<RongCloudService> _logger;
        private HttpClient _client;
        public RongCloudService(IOptions<RongCloudOption> option, IHttpClientFactory httpClientFactory, ILogger<RongCloudService> logger)
        {
            _client = httpClientFactory.CreateClient("rongcloud");
            _client.Timeout = new TimeSpan(0, 0, 10);
            _option = option?.Value;
            _logger = logger;
            var client = new MongoClient(_option.ConnectionString);
            var database = client.GetDatabase(_option.DatabaseName);
            _collection = database.GetCollection<MongoDBModel>(_option.CollectionPrefix + "RongCloud");
            _collection_user = database.GetCollection<MongoDBUserModel>(_option.CollectionPrefix + "RongCloudUser");
        }

        public Task<bool> Check(string signTimestamp, string nonce, string signature)
        {
            string sgin = GetHash(_option.AppSecret + nonce + signTimestamp);
            if (sgin.ToLower().Replace(" ", "").Equals(signature.ToLower().Replace(" ", "")))
                return Task.FromResult(true);
            else
                return Task.FromResult(false);
        }

        public async Task<(List<RongCloudModel> list, int count)> Get(string id, int userid, long timestamp, int pagecount)
        {
            var result = await _collection.Find(x => x.MKey == id).FirstOrDefaultAsync();
            if (result != null && result.UserList.Contains(userid) && result.RongCloudList != null)
            {
                var ronglist = result.RongCloudList.Where(w => Convert.ToInt64(w.MsgTimestamp) < timestamp).ToList();
                return (ronglist.OrderByDescending(x => x.MsgTimestamp).Skip((0) * pagecount).Take(pagecount).ToList(), ronglist.Count);
            }
            else
                return (new List<RongCloudModel>(), 0);
        }

        public async Task Save(RongCloudModel model)
        {
            try
            {
                //临时
                List<int> userlist = new List<int>();
                if (model.ToUserId.Length > 5)//群组Id时才访问
                {
                    try
                    {
                        var result = await _collection.Find(x => x.MKey == model.ToUserId).FirstOrDefaultAsync();
                        if (result != null && result.UserList.Count > 0)
                            userlist = result.UserList;
                        else
                            userlist = await GetUserAll(model.ToUserId);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError($"ex1:{ex.ToString()}");
                    }
                }

                var filter = Builders<MongoDBModel>.Filter.Eq("MKey", model.ToUserId);
                var update = Builders<MongoDBModel>.Update
                    .Push("RongCloudList", model)
                    .Set("RefreshTime", DateTime.Now)
                    .Set("UserList", userlist);
                await _collection.UpdateManyAsync(filter, update, new UpdateOptions() { IsUpsert = true });
            }
            catch (Exception ex)
            {
                _logger.LogError($"ex2:{ex.ToString()}");
            }
        }
        /// <summary>
        /// 创建群组成功后 添加model
        /// </summary>
        /// <param name="aduserid"></param>
        /// <param name="userid"></param>
        /// <param name="groupid"></param>
        /// <returns></returns>
        private async Task Save(int aduserid, int userid, string groupid)
        {
            try
            {
                List<int> userlist = new List<int>();
                userlist.Add(aduserid);
                userlist.Add(userid);

                var filter = Builders<MongoDBModel>.Filter.Eq("MKey", groupid);
                var update = Builders<MongoDBModel>.Update
                    .Set("RefreshTime", DateTime.Now)
                    .Set("UserList", userlist);
                await _collection.UpdateManyAsync(filter, update, new UpdateOptions() { IsUpsert = true });
            }
            catch (Exception ex)
            {
                _logger.LogError($"Save:{ex.ToString()}");
            }
        }

        private String GetHash(String input)
        {
            //建立SHA1对象
            SHA1 sha = new SHA1CryptoServiceProvider();

            //将mystr转换成byte[]
            UTF8Encoding enc = new UTF8Encoding();
            byte[] dataToHash = enc.GetBytes(input);

            //Hash运算
            byte[] dataHashed = sha.ComputeHash(dataToHash);

            //将运算结果转换成string
            string hash = BitConverter.ToString(dataHashed).Replace("-", "");

            return hash;
        }

        /// <summary>  
        /// 将c# DateTime时间格式转换为Unix时间戳格式  
        /// </summary>  
        /// <param name="time">时间</param>  
        /// <returns>long</returns>  
        private long ConvertDateTimeToInt(System.DateTime time)
        {
            DateTime startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            long t = (time.Ticks - startTime.Ticks) / 10000;   //除10000调整为13位    
            return t;
        }

        public async Task<Result> GetToken(int uid, string username)
        {
            var result = await _collection_user.Find(x => x.MKey == uid.ToString()).FirstOrDefaultAsync();
            if (result != null)
                return new Result(result.Token);

            //_logger.LogInformation("url:"+_option.Url+" key:"+_option.AppKey+" secret:"+_option.AppSecret);
            string param = $"userId={uid}&name={username}&portraitUri=''";
            var response = await HttpConnectToServer(_option.Url + "/user/getToken.json", param.Replace(" ", ""));
            if (response["code"].ToString() == "200")
            {
                string token = response["token"].ToString();
                //保存token
                var filter = Builders<MongoDBUserModel>.Filter.Eq("MKey", uid.ToString());
                var update = Builders<MongoDBUserModel>.Update
                    .Set("Token", token)
                 .Set("RefreshTime", DateTime.Now);
                await _collection_user.UpdateManyAsync(filter, update, new UpdateOptions() { IsUpsert = true });

                return new Result(token);
            }
            else
                return Result.ReFailure(response["msg"].ToString());
        }

        private async Task<dynamic> HttpConnectToServer(string url, string param)
        {
            Headers();
            //读取返回消息
            string res = string.Empty;
            try
            {
                //填充formData
                if (param == null) param = "";
                HttpContent hc = new StringContent(param, Encoding.UTF8, "application/x-www-form-urlencoded");
                _logger.LogInformation($"请求参数: {url},{param}");
                var responseMessage = await _client.PostAsync(url, hc);
                var msg = responseMessage.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                _logger.LogInformation($"响应参数: {msg}");
                if (string.IsNullOrEmpty(msg))
                    return JsonConvert.DeserializeObject<dynamic>("{\"code\":400,\"msg\":\"连接异常！\",\"time\":1531294397209,\"data\":null}");
                else
                    return JsonConvert.DeserializeObject<dynamic>(msg);
            }
            catch (Exception ex)
            {
                _logger.LogError($"RongCloudService-->HttpConnectToServer: {ex.ToString()},url:{url}");
                //连接服务器失败
                return (JObject)JsonConvert.DeserializeObject("{\"code\":400,\"msg\":\"连接异常！\",\"time\":1531294397209,\"data\":null}");
            }
        }

        private HttpClient Headers()
        {
            _client.DefaultRequestHeaders.Clear();
            string random = new Random().Next(10000, 99999).ToString();
            string timestamp = ConvertDateTimeToInt(DateTime.UtcNow).ToString();
            string sgin = GetHash(_option.AppSecret + random + timestamp);

            _client.DefaultRequestHeaders.Add("App-Key", _option.AppKey);
            _client.DefaultRequestHeaders.Add("Nonce", random);
            _client.DefaultRequestHeaders.Add("Timestamp", timestamp);
            _client.DefaultRequestHeaders.Add("Signature", sgin);

            return _client;
        }

        public async Task<Result> CreateGroup(int aduserid, int userid, string groupid, string groupname)
        {
            string param = $"userId={aduserid}&userId={userid}&groupId={groupid}&groupName={groupname}";
            var response = await HttpConnectToServer(_option.Url + "/group/create.json", param.Replace(" ", ""));

            if (response["code"].ToString() == "200")
            {
                await Save(aduserid, userid, groupid);
                return Result.ReSuccess();
            }
            else
                return Result.ReFailure("创建群组失败");
        }

        public async Task<List<int>> GetUserAll(string groupid)
        {
            string param = $"groupId={groupid}";
            var response = await HttpConnectToServer(_option.Url + "/group/user/query.json", param.Replace(" ", ""));

            if (response["code"].ToString() == "200")
            {
                List<int> list = new List<int>();
                foreach (var user in response.users)
                {
                    list.Add(Convert.ToInt32(user.id));
                }
                return list;
            }
            else
                return new List<int>();
        }
    }
}
